<template>
	<view class="e-loading-icon" :style="[addStyle(props.customStyle)]" :class="[props.vertical && 'e-loading-icon--vertical']"
		v-if="props.show">
		<view v-if="!webviewHide" class="e-loading-icon__spinner" :class="[`e-loading-icon__spinner--${props.mode}`]"
			ref="ani" :style="{
				color: color,
				width: addUnit(props.size),
				height: addUnit(props.size),
				borderTopColor: props.color,
				borderBottomColor: otherBorderColor,
				borderLeftColor: otherBorderColor,
				borderRightColor: otherBorderColor,
				'animation-duration': `${props.duration}ms`,
				'animation-timing-function': props.mode === 'semicircle' || props.mode === 'circle' ? props.timingFunction : ''
			}">
			<block v-if="props.mode === 'spinner'">
				<!-- #ifndef APP-NVUE -->
				<view v-for="(item, index) in array12" :key="index" class="e-loading-icon__dot">
				</view>
				<!-- #endif -->
				<!-- #ifdef APP-NVUE -->
				<!-- 此组件内部图标部分无法设置宽高，即使通过width和height配置了也无效 -->
				<loading-indicator v-if="!webviewHide" class="e-loading-indicator" :animating="true" :style="{
						color: props.color,
						width: addUnit(props.size),
						height: addUnit(props.size)
					}" />
				<!-- #endif -->
			</block>
		</view>
		<text v-if="text" class="e-loading-icon__text" :style="{
				fontSize: addUnit(props.textSize),
				color: props.textColor,
			}">{{props.text}}</text>
	</view>
</template>

<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * loading 加载动画
	 * @description 警此组件为一个小动画，目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
	 * @tutorial https://www.uviewui.com/components/loading.html
	 * @property {Boolean}			show			是否显示组件  (默认 true)
	 * @property {String}			color			动画活动区域的颜色，只对 mode = flower 模式有效（默认color['e-tips-color']）
	 * @property {String}			textColor		提示文本的颜色（默认color['e-tips-color']）
	 * @property {Boolean}			vertical		文字和图标是否垂直排列 (默认 false )
	 * @property {String}			mode			模式选择，见官网说明（默认 'circle' ）
	 * @property {String | Number}	size			加载图标的大小，单位px （默认 24 ）
	 * @property {String | Number}	textSize		文字大小（默认 15 ）
	 * @property {String | Number}	text			文字内容 
	 * @property {String}			timingFunction	动画模式 （默认 'ease-in-out' ）
	 * @property {String | Number}	duration		动画执行周期时间（默认 1200）
	 * @property {String}			inactiveColor	mode=circle时的暗边颜色 
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * @example <e-loading mode="circle"></e-loading>
	 */
	export default defineComponent({
		name: 'e-loading-icon',
		mixins: [mpMixin]
	})
</script>

<script lang="ts" setup>
	import {
		ref,
		computed,
		watch,
		onMounted,
		toRefs
	} from 'vue'
	import {
		loadingIconProps
	} from './props';
	import {
		useDefaultProps,
		useWebviewEvent
	} from '../../libs/hooks'
	import {
		colorGradient
	} from '../../libs/utils'
	import {
		addUnit,
		addStyle
	} from '../../libs/utils/_utils'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";


	



	const {
		loadingIcon: loadingIconDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(loadingIconProps)
	const props = useDefaultProps < DefaultProps['loadingIcon'] > (_props, loadingIconDefaultProps);


	// Array.form可以通过一个伪数组对象创建指定长度的数组
	const array12 = ref(Array.from({
		length: 12
	}))
	// 这里需要设置默认值为360，否则在安卓nvue上，会延迟一个duration周期后才执行
	// 在iOS nvue上，则会一开始默认执行两个周期的动画
	let aniAngel = 360 // 动画旋转角度
	const loading = ref(false) // 是否运行中，针对nvue使用
	const ani = ref(null) //ani Refs对象
	
	const {webviewHide,addEventListenerToWebview} = useWebviewEvent()

	// 当为circle类型时，给其另外三边设置一个更轻一些的颜色
	// 之所以需要这么做的原因是，比如父组件传了color为红色，那么需要另外的三个边为浅红色
	// 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝，导致效果没有那么细腻良好)
	const otherBorderColor = computed(() => {
		const lightColor = colorGradient(props.value.color, '#ffffff', 100)[80]
		if (props.value.mode === 'circle') {
			return props.value.inactiveColor ? props.value.inactiveColor : lightColor
		} else {
			return 'transparent'
		}
	})


	const init = () => {
		setTimeout(() => {
			// #ifdef APP-NVUE
			props.value.show && nvueAnimate()
			// #endif
			// #ifdef APP-PLUS 
			props.value.show && addEventListenerToWebview()
			// #endif
		}, 20)
	}
	
	// #ifdef APP-NVUE
	const nvueAnimate = () => {
		// nvue下，非spinner类型时才需要旋转，因为nvue的spinner类型，使用了weex的
		// loading-indicator组件，自带旋转功能
		props.value.mode !== 'spinner' && startAnimate()
	}
	let animation:any
	// 执行nvue的animate模块动画
	const startAnimate = () => {
		loading.value = true
		if (!ani.value) return
		if(!animation){
			animation = uni.requireNativePlugin('animation');
		}
		
		animation.transition(ani.value, {
			// 进行角度旋转
			styles: {
				transform: `rotate(${aniAngel}deg)`,
				transformOrigin: 'center center'
			},
			duration: props.value.duration,
			timingFunction: props.value.timingFunction,
			// delay: 10
		}, () => {
			// 每次增加360deg，为了让其重新旋转一周
			aniAngel += 360
			// 动画结束后，继续循环执行动画，需要同时判断webviewHide变量
			// nvue安卓，页面隐藏后依然会继续执行startAnimate方法
			props.value.show && !webviewHide.value ? startAnimate() : loading.value = false
		})
	}
	// #endif


	watch(() => props.value.show, (n) => {
		// nvue中，show为true，且为非loading状态，就重新执行动画模块
		// #ifdef APP-NVUE
		if (n && !loading.value) {
			setTimeout(() => {
				startAnimate()
			}, 30)
		}
		// #endif
	})

	onMounted(() => {
		init()
	})
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/loading-icon.scss";
	/* #ifndef APP-NVUE */
	@import "../../libs/theme/loading-icon-no-nvue.scss";
	/* #endif */
</style>
